﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Veralkohol.Converters;

namespace Veralkohol
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Veralkohol.MyControls"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Veralkohol.MyControls;assembly=Veralkohol.MyControls"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:AlcoholPlot/>
    ///
    /// </summary>
    public class AlcoholPlot : Control
    {
        protected ObservableCollection<Line> YaxisLines = new ObservableCollection<Line>();
        protected ObservableCollection<TextBlock> YaxisTexts = new ObservableCollection<TextBlock>();

        protected ObservableCollection<Line> XaxisLines = new ObservableCollection<Line>();
        protected ObservableCollection<TextBlock> XaxisTexts = new ObservableCollection<TextBlock>();

        protected double YaxisPointCount = 0; //Only init, this will means YTo - YFrom
        protected double YaxisDistance = 0; //Only init, this will means 1 ‰
        protected double YaxisHeight = 0; //Only init, this will means the length of Y axis
        protected const double YaxisFromLeft = 35;

        protected double XaxisPointCount = 0; //Only init, this will means XTo - XFrom
        protected double XaxisDistance = 0; //Only init, this will means 1 hour
        protected double XaxisWidth = 0; //Only init, this will means the length of X axis
        protected const double XaxisFromBottom = 41;
        protected const double XaxisFromRight = 15;

        public event EventHandler DiagramChanged;

        #region Points - DProp

        public ObservableCollection<AlcoholDiagramPoint> Points
        {
            get { return (ObservableCollection<AlcoholDiagramPoint>)GetValue(PointsProperty); }
            set { SetValue(PointsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Lines.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PointsProperty =
            DependencyProperty.Register("Points", typeof(ObservableCollection<AlcoholDiagramPoint>), typeof(AlcoholPlot),
            new PropertyMetadata(new ObservableCollection<AlcoholDiagramPoint>()));

        #endregion

        #region VerticalGridVisible - DProp

        public bool VerticalGridVisible
        {
            get { return (bool)GetValue(VerticalGridVisibleProperty); }
            set { SetValue(VerticalGridVisibleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for VerticalGridVisible.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VerticalGridVisibleProperty =
            DependencyProperty.Register("VerticalGridVisible", typeof(bool), typeof(AlcoholPlot), new PropertyMetadata(false));

        #endregion

        #region XFrom - DProp

        public string XFrom
        {
            get { return (string)GetValue(XFromProperty); }
            set { SetValue(XFromProperty, value); }
        }

        // Using a DependencyProperty as the backing store for XFrom.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty XFromProperty =
            DependencyProperty.Register("XFrom", typeof(string), typeof(AlcoholPlot),
            new PropertyMetadata("0.00:00", new PropertyChangedCallback(XFromChangedCallback)));

        private static void XFromChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            AlcoholPlot diagram = sender as AlcoholPlot;
            if (diagram.XFrom == "Auto")
            {
                var now = DateTime.Now;

                diagram.XFrom = string.Format("0.{0}:{1}", now.Hour, now.Minute);
            }

            diagram.XaxisLines.Clear();
            diagram.XaxisTexts.Clear();

            diagram.DrawXaxis(reScale: true);
        }

        #endregion

        #region XTo - DProp

        public string XTo
        {
            get { return (string)GetValue(XToProperty); }
            set { SetValue(XToProperty, value); }
        }

        // Using a DependencyProperty as the backing store for XTo.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty XToProperty =
            DependencyProperty.Register("XTo", typeof(string), typeof(AlcoholPlot),
            new PropertyMetadata("0.00:00", new PropertyChangedCallback(XToChangedCallback)));

        private static void XToChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            AlcoholPlot diagram = sender as AlcoholPlot;
            if (diagram.XTo == "Auto")
            {
                string xff = "";
                if (diagram.XFrom == "Auto")
                {
                    var now = DateTime.Now;
                    xff = string.Format("0.{0}:{1}", now.Hour, now.Minute);
                }
                else
                {
                    xff = diagram.XFrom;
                }

                var xf = xff.Split(new[] { '.', ':' });
                double xfdate = int.Parse(xf[0]) * 24 + int.Parse(xf[1]) + double.Parse(xf[2]) / 60.0;
                var now_10 = xfdate + 11;

                int dd = (int)(now_10 / 24);
                int hh = (int)(now_10 - dd * 24);
                int mm = (int)Math.Round((now_10 - dd * 24 - hh) * 60, 0);

                diagram.XTo = string.Format("{0}.{1}:00", dd, hh);
            }

            diagram.XaxisLines.Clear();
            diagram.XaxisTexts.Clear();

            diagram.DrawXaxis(reScale: true);
        }

        #endregion

        #region YFrom - DProp

        public double YFrom
        {
            get { return (double)GetValue(YFromProperty); }
            set { SetValue(YFromProperty, value); }
        }

        // Using a DependencyProperty as the backing store for YFrom.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty YFromProperty =
            DependencyProperty.Register("YFrom", typeof(double), typeof(AlcoholPlot), new PropertyMetadata(0.0));

        #endregion

        #region YTo - DProp

        public double YTo
        {
            get { return (double)GetValue(YToProperty); }
            set { SetValue(YToProperty, value); }
        }

        // Using a DependencyProperty as the backing store for YTo.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty YToProperty =
            DependencyProperty.Register("YTo", typeof(double), typeof(AlcoholPlot), new PropertyMetadata(5.0));

        #endregion

        #region ScreenLeft

        public double ScreenLeft
        {
            get { return (double)GetValue(ScreenLeftProperty); }
            set { SetValue(ScreenLeftProperty, value); }
        }

        // Using a DependencyProperty as the backing store for YTo.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScreenLeftProperty =
            DependencyProperty.Register("ScreenLeft", typeof(double), typeof(AlcoholPlot), new PropertyMetadata(0.0));

        #endregion

        #region ScreenTop

        public double ScreenTop
        {
            get { return (double)GetValue(ScreenTopProperty); }
            set { SetValue(ScreenTopProperty, value); }
        }

        // Using a DependencyProperty as the backing store for YTo.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScreenTopProperty =
            DependencyProperty.Register("ScreenTop", typeof(double), typeof(AlcoholPlot), new PropertyMetadata(0.0));

        #endregion

        #region Axis drawing functions

        protected void DrawYaxis(bool reDraw = false, bool reScale = false, SizeChangedEventArgs e = null)
        {
            Canvas Yaxis = this.GetTemplateChild("Yaxis") as Canvas;
            if (Yaxis != null)
            {
                //Initialize variables
                if (reDraw)
                {
                    YaxisHeight = e.NewSize.Height - XaxisFromBottom;
                }
                YaxisPointCount = YTo - YFrom;
                YaxisDistance = YaxisHeight / YaxisPointCount;

                //Draw the axis
                if (!reDraw) YaxisLines.Add(new Line().CreateLine(YaxisFromLeft, 5, YaxisFromLeft, YaxisHeight + 5));

                double ystep = YaxisHeight + 5;
                Special.DFOR(YFrom, YTo + 0.3, YaxisPointCount - (int)YaxisPointCount, 1, (val, i, first) =>
                    {
                        if (reDraw)
                        {
                            Canvas.SetTop(YaxisTexts[i], ystep - 7);
                            if (i == 0)
                            {
                                YaxisLines[i].Y2 = YaxisHeight + 5;
                            }
                            else
                            {
                                YaxisLines[i].Y1 = YaxisLines[i].Y2 = ((i - 1) * YaxisDistance) + 5;
                            }
                        }
                        else
                        {
                            TextBlock tb = new TextBlock();
                            tb.Foreground = Brushes.WhiteSmoke;
                            tb.FontFamily = new System.Windows.Media.FontFamily("Ubuntu");
                            tb.Text = val + "‰";
                            Canvas.SetTop(tb, ystep - 7);
                            YaxisTexts.Add(tb);

                        }
                        if (first)
                        {
                            ystep -= ((int)val + 1 - val) * YaxisDistance;
                        }
                        else
                        {
                            if (!reDraw)
                            {
                                YaxisLines.Add(new Line().CreateLine(
                                    YaxisFromLeft - 2.5, ystep, YaxisFromLeft + 2.5, ystep
                                    ));
                            }
                            ystep -= YaxisDistance;
                        }
                    });


                //Add elements to canvas
                if (!reDraw)
                {
                    foreach (var item in YaxisLines)
                    {
                        Yaxis.Children.Add(item);
                    }
                    foreach (var item in YaxisTexts)
                    {
                        Yaxis.Children.Add(item);
                    }
                }
            }


        }

        protected void DrawXaxis(bool reDraw = false, bool reScale = false, SizeChangedEventArgs e = null)
        {
            Canvas Xaxis = this.GetTemplateChild("Xaxis") as Canvas;
            if (Xaxis != null)
            {
                if (reScale)
                {
                    Xaxis.Children.Clear();
                }

                //Initialize variables
                double ftime = Special.stringTime2double(XFrom);
                double ttime = Special.stringTime2double(XTo);

                if (!reScale)
                {
                    if (reDraw) XaxisWidth = e.NewSize.Width - YaxisFromLeft - XaxisFromRight;
                    else XaxisWidth = 784 - YaxisFromLeft - XaxisFromRight;
                }
                XaxisPointCount = ttime - ftime;
                XaxisDistance = XaxisWidth / XaxisPointCount;

                //Draw the axis
                XaxisLines.Add(new Line().CreateLine(YaxisFromLeft, YaxisHeight + 5, YaxisFromLeft + XaxisWidth, YaxisHeight + 5));

                double xstep = YaxisFromLeft;
                Special.DFOR(ftime, ttime + 0.3, XaxisPointCount - (int)XaxisPointCount, 1, (val, i, first) =>
                    {
                        TextBlock tb = new TextBlock();
                        if (reDraw)
                        {
                            Canvas.SetLeft(XaxisTexts[i], xstep - 18);
                            Canvas.SetTop(XaxisTexts[i], YaxisHeight + 7);
                            if (i == 0)
                            {
                                XaxisLines[i].X2 = XaxisWidth + YaxisFromLeft;
                                XaxisLines[i].Y1 = XaxisLines[i].Y2 = YaxisHeight + 5;
                            }
                            else
                            {
                                XaxisLines[i].X1 = XaxisLines[i].X2 = XaxisWidth + YaxisFromLeft - ((i - 1) * XaxisDistance);
                                XaxisLines[i].Y1 = YaxisHeight;
                                XaxisLines[i].Y2 = YaxisHeight + 10;
                            }
                        }
                        else
                        {

                            tb.Foreground = Brushes.WhiteSmoke;
                            tb.FontFamily = new System.Windows.Media.FontFamily("Ubuntu");
                            Canvas.SetLeft(tb, xstep - 18);
                            Canvas.SetTop(tb, YaxisHeight + 7);

                        }
                        if (first)
                        {
                            xstep += ((int)val + 1 - val) * XaxisDistance;
                        }
                        else
                        {
                            XaxisLines.Add(new Line().CreateLine(
                                xstep,
                                YaxisHeight,
                                xstep,
                                YaxisHeight + 10));

                            int dd = (int)(val / 24);
                            int hh = (int)(val - dd * 24);
                            int mm = (int)Math.Round((val - dd * 24 - hh) * 60, 0);

                            if (!reDraw) tb.Text = string.Format("{0}. nap\n{1}:{2}", dd, Special.int2twochar(hh), Special.int2twochar(mm));
                            xstep += XaxisDistance;
                        }
                        if (!reDraw) XaxisTexts.Add(tb);
                    }
                );

                //Add elements to the canvas
                if (!reDraw)
                {
                    foreach (var item in XaxisLines)
                    {
                        Xaxis.Children.Add(item);
                    }
                    foreach (var item in XaxisTexts)
                    {
                        Xaxis.Children.Add(item);
                    }
                }
            }
        }

        #endregion


        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            Points.CollectionChanged += Points_CollectionChanged;

            if (XFrom == "Auto" || XTo == "Auto")
            {
                var now = DateTime.Now;
                var now_10 = DateTime.Now.AddHours(11);

                XFrom = string.Format("0.{0}:{1}", now.Hour, now.Minute);
                XTo = string.Format("{0}.{1}:00", now_10.Day - now.Day, now_10.Hour);
            }

            DrawYaxis();
            DrawXaxis();

            Canvas canvas = this.GetTemplateChild("canvas") as Canvas;
            if (canvas != null)
            {
                canvas.SizeChanged += canvas_SizeChanged;
            }

            Canvas vgrid = this.GetTemplateChild("verticalgrid") as Canvas;
            if (vgrid != null)
            {
                //Drawing vertical grid
                //for (int i = 500; i > 0; i-=20)
                //{
                //    Line gridline = new Line();
                //    gridline.Stroke = System.Windows.Media.Brushes.Gray;
                //    gridline.StrokeThickness = 1;
                //    gridline.X1 = 0;
                //    gridline.X2 = 600;
                //    gridline.Y1 = gridline.Y2 = i;
                //    vgrid.Children.Add(gridline);
                //}

                //Bindig to vertical grid
                Binding b = new Binding("Visibility");
                b.Mode = BindingMode.TwoWay;
                b.Source = VerticalGridVisible;
                b.Converter = new Bool2VisibilityConverter();
                vgrid.SetBinding(Canvas.VisibilityProperty, b);
                //BindingOperations.ClearBinding(
            }
        }

        void canvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            DrawYaxis(reDraw: true, e: e);
            DrawXaxis(reDraw: true, e: e);

            Canvas canvas = this.GetTemplateChild("canvas") as Canvas;
            if (canvas != null)
            {
                try
                {

                    foreach (var item in Points)
                    {
                        double timeDistance = item.DrinkTime - Special.stringTime2double(XFrom);
                        double thousDistance = item.Thousandths - YFrom;
                        Canvas.SetLeft(item, timeDistance * XaxisDistance + YaxisFromLeft);
                        Canvas.SetTop(item, YaxisHeight - thousDistance * YaxisDistance + 5);
                        item.Height = item.Thousandths * YaxisDistance ;// -YaxisHeight / 40; //YaxisHeight/40 -> ennyit téved a magasság
                    }
                }
                catch { }
            }
        }

        void Points_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //if (!(e.NewItems[0] as AlcoholDiagramPoint).isControlPoint) return;
            

            Canvas canvas = this.GetTemplateChild("canvas") as Canvas;
            Canvas toolcanvas = this.GetTemplateChild("tooltip") as Canvas;
            Canvas toolcanvas2 = this.GetTemplateChild("tooltip2") as Canvas;
            if (canvas != null)
            {
                switch (e.Action)
                {
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                        AlcoholDiagramPoint newItem = e.NewItems[0] as AlcoholDiagramPoint;
                        int ni = e.NewStartingIndex;
                        Points[ni].PointSelected += (s, pse) =>
                        {
                            int index = ni;
                            string message = pse.SelectedPoint.ToString();
                            if (newItem == Points[Points.Count - 1])
                            {
                                double endtime = Points[ni].GetZero();
                                int dd = (int)(endtime / 24);
                                int hh = (int)(endtime - dd * 24);
                                int mm = (int)Math.Round((endtime - dd * 24 - hh) * 60, 0);
                                message += string.Format("\n\nVárható kijózanodás ideje: {0}.nap {1}:{2}", dd, hh, mm);
                            }

                            AlcoholTooltip ttip = new AlcoholTooltip(pse.SelectedPoint, newItem == Points[Points.Count - 1], !pse.SelectedPoint.isControlPoint);

                            //MessageBox.Show(string.Format("{0}-{1}", 
                            //    System.Windows.Forms.Control.MousePosition.X-ScreenLeft, 
                            //    System.Windows.Forms.Control.MousePosition.Y-ScreenTop));

                            Point poi = new Point(System.Windows.Forms.Control.MousePosition.X - ScreenLeft, 
                                System.Windows.Forms.Control.MousePosition.Y - ScreenTop);

                            if (poi.X <= XaxisWidth + XaxisFromRight + YaxisFromLeft - 265)
                            {
                                Canvas.SetLeft(ttip, poi.X);
                            }
                            else
                            {
                                Canvas.SetLeft(ttip, poi.X - 265);
                            }

                            if (poi.Y < YaxisHeight + 5 - 160)
                            {
                                Canvas.SetTop(ttip, poi.Y);
                            }
                            else
                            {
                                Canvas.SetTop(ttip, poi.Y - 160);
                            }
                            ttip.TooltipClosed += (s1, e1) =>
                                {
                                    AnimateToolTip(ref toolcanvas, true);
                                    AnimateToolTip(ref toolcanvas2, true);
                                    toolcanvas2.Children.Remove(s1 as AlcoholTooltip);
                                };

                            toolcanvas2.Children.Add(ttip);

                            ttip.DrinkDeleted += (s2, e2) =>
                                {
                                    //MessageBox.Show((s2 as Drink).ToString());
                                    int ind = Points.IndexOf(e2.SelectedPoint);
                                    Points[ind].Drinks.Remove(s2 as Drink);
                                    if (Points[ind].Drinks.Count == 0)
                                    {
                                        Points[ind].isControlPoint = false;
                                    }
                                    for (int i = index-1 < 0 ? 0 : index-1; i < Points.Count; i++)
                                    {
                                        AnimatePoint(i);
                                    }
                                    if (DiagramChanged != null) DiagramChanged(this, null);
                                };

                            ttip.AllDrinkDeleted += (s3, e3) =>
                                {
                                    int ind = Points.IndexOf(e3.SelectedPoint);
                                    Points[ind].Drinks.Clear();
                                    Points[ind].isControlPoint = false;
                                    for (int i = index - 1 < 0 ? 0 : index - 1; i < Points.Count; i++)
                                    {
                                        AnimatePoint(i);
                                    }
                                    if (DiagramChanged != null) DiagramChanged(this, null);
                                };

                            AnimateToolTip(ref toolcanvas);
                            AnimateToolTip(ref toolcanvas2, auto: false);

                        };
                        if (Points.Count == 1)
                        {
                            PlacePoint(ni, ref canvas);
                            AnimatePoint(ni);
                        }
                        else
                        {
                            bool modified = false;
                            int i = 0;
                            for (; i < Points.Count - 1; i++)
                            {
                                if (newItem.ComparableDrinkTime < Points[i].ComparableDrinkTime)
                                {
                                    Points.Move(ni, i);
                                    //Bind forward
                                    Binding thousBindFW = new Binding("THIS");
                                    thousBindFW.Source = Points[i];
                                    Points[i + 1].SetBinding(AlcoholDiagramPoint.LastReferencePointProperty, thousBindFW);
                                    //Bind backward
                                    if (i == 0)
                                    {
                                        Points[i].LastReferencePoint = null;
                                    }
                                    else
                                    {
                                        Binding thousBindBW = new Binding("THIS");
                                        thousBindBW.Source = Points[i - 1];
                                        Points[i].SetBinding(AlcoholDiagramPoint.LastReferencePointProperty, thousBindBW);
                                    }
                                    modified = true;
                                    PlacePoint(i, ref canvas);
                                    AnimatePoint(i);
                                    break;
                                }
                                else if (newItem.ComparableDrinkTime == Points[i].ComparableDrinkTime)
                                {
                                    if (!Points[i].isControlPoint)
                                    {
                                        Points[i].isControlPoint = true;
                                        Points[i].Drinks.Clear();
                                    }
                                    Points[i].Drinks.Add(Drink.CloneNewInstance(newItem.Drinks[0]));
                                    Points.RemoveAt(ni);
                                    AnimatePoint(i);
                                    modified = true;
                                    break;
                                }
                            }
                            if (!modified)
                            {
                                int lastTime = Points[ni - 1].ComparableDrinkTime;
                                int finishTime = Points[ni].ComparableDrinkTime;

                                Binding thousBind = new Binding("THIS");
                                thousBind.Source = Points[ni - 1];
                                Points[ni].SetBinding(AlcoholDiagramPoint.LastReferencePointProperty, thousBind);
                                PlacePoint(ni, ref canvas);
                                AnimatePoint(ni);
                                for (int time = lastTime + 10, iter = ni; time <= finishTime - 10; time += 10, iter++)
                                {
                                    Points.Add(new AlcoholDiagramPoint(newItem.Weight, time));
                                }
                            }
                            else
                            {
                                for (i += 1; i < Points.Count; i++)
                                {
                                    AnimatePoint(i);
                                }
                            }
                        }
                        break;
                    #region NOT USE
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Move:
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                        break;
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                        break;
                    #endregion
                    case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                        canvas.Children.Clear();
                        if (DiagramChanged != null) DiagramChanged(this, null);
                        break;
                    default:
                        break;
                }
            }
            if (DiagramChanged != null) DiagramChanged(this, null);
        }

        static AlcoholPlot()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AlcoholPlot), new FrameworkPropertyMetadata(typeof(AlcoholPlot)));
        }

        private void PlacePoint(int i, ref Canvas c, bool replace = false)
        {
            double timeDistance = Points[i].DrinkTime - Special.stringTime2double(XFrom);
            double thousDistance = Points[i].Thousandths - YFrom;

            Canvas.SetLeft(Points[i], timeDistance * XaxisDistance + YaxisFromLeft);
            Canvas.SetTop(Points[i], YaxisHeight + 5);
            Points[i].Height = 0;

            c.Children.Add(Points[i]);
        }

        private void AnimateToolTip(ref Canvas c, bool hide = false, bool auto = true)
        {
            double to = auto ? 0.7 : 1;
            if (hide)
            {
                DoubleAnimation da = new DoubleAnimation();
                da.To = 0;
                da.Duration = new Duration(TimeSpan.FromSeconds(1));
                Storyboard.SetTarget(da, c);
                Storyboard.SetTargetProperty(da, new PropertyPath("Opacity"));
                Storyboard sb = new Storyboard();
                sb.Children.Add(da);
                sb.Completed += (s, ce) =>
                {
                    Canvas toolc = this.GetTemplateChild("tooltip") as Canvas;
                    Canvas toolc2 = this.GetTemplateChild("tooltip2") as Canvas;
                    toolc.Opacity = 0;
                    toolc2.Opacity = 0;
                    toolc.ApplyAnimationClock(Canvas.OpacityProperty, null);
                    toolc2.ApplyAnimationClock(Canvas.OpacityProperty, null);
                    toolc.Visibility = System.Windows.Visibility.Hidden;
                    toolc2.Visibility = System.Windows.Visibility.Hidden;
                };
                sb.Begin();
            }
            else
            {
                c.Visibility = System.Windows.Visibility.Visible;
                DoubleAnimation da = new DoubleAnimation();
                da.To = to;
                da.Duration = new Duration(TimeSpan.FromSeconds(1));
                Storyboard.SetTarget(da, c);
                Storyboard.SetTargetProperty(da, new PropertyPath("Opacity"));
                Storyboard sb = new Storyboard();
                sb.Children.Add(da);
                sb.Completed += (s, ce) =>
                {
                    Canvas toolc = this.GetTemplateChild("tooltip") as Canvas;
                    Canvas toolc2 = this.GetTemplateChild("tooltip2") as Canvas;
                    toolc.Opacity = 0.7;
                    toolc2.Opacity = 1;
                    toolc.ApplyAnimationClock(Canvas.OpacityProperty, null);
                    toolc2.ApplyAnimationClock(Canvas.OpacityProperty, null);
                };
                sb.Begin();
            }
        }

        private void AnimatePoint(int i)
        {
            double timeDistance = Points[i].DrinkTime - Special.stringTime2double(XFrom);
            double thousDistance = Points[i].Thousandths - YFrom;

            DoubleAnimation da = new DoubleAnimation();
            da.To = Points[i].Thousandths * YaxisDistance + 5;// - YaxisHeight / 40; //YaxisHeight/40 -> ennyit téved a magasság
            da.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTarget(da, Points[i]);
            Storyboard.SetTargetProperty(da, new PropertyPath("Height"));

            DoubleAnimation da3 = new DoubleAnimation();
            da3.To = YaxisHeight - thousDistance * YaxisDistance ;
            da3.Duration = new Duration(TimeSpan.FromSeconds(1));
            Storyboard.SetTarget(da3, Points[i]);
            Storyboard.SetTargetProperty(da3, new PropertyPath("(Canvas.Top)"));

            Storyboard sb = new Storyboard();
            sb.Children.Add(da);
            sb.Children.Add(da3);

            sb.Completed += (s, ce) =>
            {
                Points[i].Height = Points[i].Thousandths * YaxisDistance ;// -YaxisHeight / 40; //YaxisHeight/40 -> ennyit téved a magasság
                Canvas.SetTop(Points[i], YaxisHeight - thousDistance * YaxisDistance + 5);
                Points[i].ApplyAnimationClock(Canvas.TopProperty, null);
                Points[i].ApplyAnimationClock(AlcoholDiagramPoint.HeightProperty, null);
            };
            sb.Begin();
        }


    }

    #region Static FOR cycle with DOUBLE type parameters

    public static class Special
    {
        public static void DFOR(double i, double to, double? firstAddition, double otherAddition, Action<double, int, bool> work)
        {
            double iter = i;
            int count = 0;
            bool first = true;

            Double a = firstAddition == null ? 0 : (double)firstAddition;
            if (iter < to)
            {
                while (iter < to)
                {
                    if (firstAddition != null && a.CompareTo(0) != 0 && a.CompareTo(otherAddition) != 0)
                    {
                        work(iter, count, first);
                        if (first)
                        {
                            iter += (double)firstAddition;
                            first = false;
                        }
                        else
                        {
                            iter += otherAddition;
                        }
                    }
                    else
                    {
                        work(iter, count, false);
                        iter += otherAddition;
                    }
                    count++;
                }
            }
            else if (iter > to)
            {
                while (iter > to)
                {
                    if (firstAddition != null && a.CompareTo(0) != 0 && a.CompareTo(otherAddition) != 0)
                    {
                        work(iter, count, first);
                        if (first)
                        {
                            iter -= (double)firstAddition;
                            first = false;
                        }
                        else
                        {
                            iter -= otherAddition;
                        }
                    }
                    else
                    {
                        work(iter, count, false);
                        iter -= otherAddition;
                    }
                    count++;
                }
            }
            else work(iter, 0, true);
        }

        public static string int2twochar(int a)
        {
            return a < 10 && a >= 0 ? "0" + a : a.ToString();
        }

        public static double stringTime2double(string time)
        {
            string time2 = time.Contains(".") ? time : "0." + time;

            var timearray = time2.Split(new[] { '.', ':' });
            double dtime = 0;
            try
            {
                dtime = int.Parse(timearray[0]) * 24 + int.Parse(timearray[1]) + double.Parse(timearray[2]) / 60;
            }
            catch { }

            return dtime;
        }
    }

    #endregion

    #region Line extension methods

    public static class LineHelper
    {
        public static Line CreateLine(this Line l, double X1, double Y1, double X2, double Y2)
        {
            l = new Line();
            l.X1 = X1;
            l.X2 = X2;
            l.Y1 = Y1;
            l.Y2 = Y2;
            l.StrokeThickness = 1;
            l.Stroke = Brushes.WhiteSmoke;
            return l;
        }
    }

    #endregion

    #region COMMENTED - AlcoholicPoint old class

    //public class AlcoholicPoint
    //{
    //    double startthosandths = 0;

    //    public double Quantity { get; set; }
    //    public double Percentage { get; set; }
    //    public double Weight { get; set; }
    //    public double DrinkTime { get; set; }
    //    public bool Drawed { get; set; }

    //    public double Thousandths
    //    {
    //        get
    //        {
    //            return ((Quantity * Percentage * 0.8) / Weight) + startthosandths;
    //        }
    //        set
    //        {
    //            startthosandths += value;
    //        }
    //    }

    //    public AlcoholicPoint(double weight, double quantity, double percentage, int day, int hour, int minute, double startThousandths)
    //    {
    //        DrinkTime = day * 24 + hour + (double)minute / 60;
    //        Quantity = quantity;
    //        Percentage = percentage;
    //        Weight = weight;
    //        startthosandths = startThousandths;
    //        Drawed = false;
    //    }

    //    public AlcoholicPoint(double weight, double quantity, double percentage, double drinktime)
    //    {
    //        DrinkTime = drinktime;
    //        Quantity = quantity;
    //        Percentage = percentage;
    //        Weight = weight;
    //        Drawed = false;
    //    }

    //    public AlcoholicPoint(double weight, double quantity, double percentage, int day, int hour, int minute)
    //    {
    //        DrinkTime = day * 24 + hour + (double)minute / 60;
    //        Quantity = quantity;
    //        Percentage = percentage;
    //        Weight = weight;
    //        Drawed = false;
    //    }

    //    public AlcoholicPoint(AlcoholicPoint p, double startThousandths, bool drawed)
    //    {
    //        DrinkTime = p.DrinkTime;
    //        Drawed = drawed;
    //        Quantity = p.Quantity;
    //        Percentage = p.Percentage;
    //        Weight = p.Weight;
    //        startthosandths = startThousandths;
    //    }

    //    public static double GetThousandths(double fromTime, double toTime, double thousandths)
    //    {
    //        double timedist = toTime - fromTime;
    //        double newthou = thousandths - (int)timedist * 0.15 - (timedist - (int)timedist) * 0.0025;

    //        return newthou <= 0 ? 0 : newthou;
    //    }

    //    public double GetZero(ObservableCollection<AlcoholicPoint> points)
    //    {
    //        AlcoholicPoint p = points[points.Count - 1];
    //        double time = p.Thousandths / 0.15;
    //        return p.DrinkTime + time;
    //    }

    //    public override string ToString()
    //    {
    //        int dd = (int)(DrinkTime / 24);
    //        int hh = (int)(DrinkTime - dd * 24);
    //        int mm = (int)Math.Round((DrinkTime - dd * 24 - hh) * 60, 0);
    //        return string.Format("{0}% | {1} dl | {2} kg | {3}.{4}:{5} ", Percentage, Quantity, Weight, dd, hh, mm);
    //    }

    //}
    #endregion
}
